﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection.Metadata;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using Microsoft.Build.Construction;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.MSBuild;
using Microsoft.CodeAnalysis.Text;
using static Lhxzn.LangExtractor.IniFile;
using Document = Microsoft.CodeAnalysis.Document;

#region 文件信息
/****************************************************************
*	公司名称：福建力和行智能科技有限公司
*   作    者：Jeff
*   CLR 版本：4.0.30319.42000
*   创建时间：12/19/2024 3:46:21 PM
*	用 户 名：zheqichen 
*   描述说明：
*
*   修改历史：
*		1）	修 改 人：
*			修改日期：
*			修改内容：			
*
*****************************************************************/
#endregion

namespace Lhxzn.LangExtractor
{
    /// <summary>
    /// 类    名:LangExtractorHelper
    /// 描    述:语言档提取工具
    /// 修改时间:12/19/2024 3:46:21 PM
    /// </summary>
    public static class LangExtractorHelper
    {
        #region 成员变量

        #region private



        #endregion


        #region protected



        #endregion


        #region public

        #endregion

        #endregion


        #region 构造函数
        ///// <summary>
        ///// 函 数 名:构造函数
        ///// 函数描述:默认构造函数
        ///// 修改时间:12/19/2024 3:46:21 PM
        ///// </summary>
        //public LangExtractorHelper()
        //{

        //}
        #endregion

        #region 父类函数重载、接口实现

        #endregion

        #region 函数

        #region private



        #endregion


        #region protected



        #endregion


        #region public
        /// <summary>
        /// 根据路径获取解决方案对象
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static async Task<Solution> GetSolution(string path)
        {
            //Directory.CreateDirectory(OutputPath);
            using var workspace = MSBuildWorkspace.Create();
            return await workspace.OpenSolutionAsync(path);
        }

        /// <summary>
        /// 根据路径获取解决方案对象
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static async Task<Project> GetProject(string path)
        {
            //Directory.CreateDirectory(OutputPath);
            using var workspace = MSBuildWorkspace.Create();
            return await workspace.OpenProjectAsync(path);
        }


        /// <summary>
        /// 从解决方案中提取语言文件
        /// </summary>
        public static async Task<LanguagePackage> ExtractLangFromSolution(Solution solution,string outputFolderPath)
        {
            List<LanguageFile> files = new List<LanguageFile>();
            foreach (var project in solution.Projects)
            {
                // 获取项目文件路径
                var projectFilePath = project.OutputFilePath;
                var projectFileName = Path.GetFileNameWithoutExtension(projectFilePath);
                string outputPath=Path.Combine(outputFolderPath, projectFileName+ ".lng");
                files.Add(await ExtractLangFromProject(project));
            }
            LanguagePackage package = new LanguagePackage(outputFolderPath) { LanguageFiles = files };
            package.SetPackagePath(outputFolderPath);
            files.Select(file=>file.Package= package);

            return package;
        }

        /// <summary>
        /// 从项目中提取语言键值对
        /// </summary>
        /// <param name="project"></param>
        /// <returns></returns>
        public static async Task<LanguageFile> ExtractLangFromProject(Project project)
        {
            // 获取项目文件路径
            var projectFilePath = project.OutputFilePath;
            var projectFileName = Path.GetFileNameWithoutExtension(projectFilePath);
            var directoryName = Path.GetDirectoryName(projectFilePath);
            LanguageFile file = new LanguageFile(Path.Combine(directoryName,projectFileName + ".lng"));
            foreach (var document in project.Documents)
            {
                await ExtractLangFromCsFile(document, file);
            }
            await ExtractUINames(project, file);
            return file;
        }

        /// <summary>
        /// 提取LanguageMgr.Read()
        /// </summary>
        /// <param name="root"></param>
        /// <param name="file"></param>
        public static void ExtractLanguageMgrRead(SyntaxNode root,LanguageFile file)
        {
            var className = GetClassNameFromDocument(root);
            if (string.IsNullOrEmpty(className))
            {
                return;
            }

            // 查找所有调用LanguageMgr.Read的地方
            var invocations = root.DescendantNodes().OfType<InvocationExpressionSyntax>();
            foreach (var invocation in invocations)
            {
                if (IsLanguageMgrReadInvocation(invocation))
                {
                    var stringLiteral = ExtractStringLiteralFromInvocation(invocation);
                    if (stringLiteral != null)
                    {
                        file.ReadValue(className, stringLiteral);
                    }
                }
            }
        }

        /// <summary>
        /// 提取ALLAttribute
        /// </summary>
        /// <param name="root"></param>
        /// <param name="file"></param>
        public static void ExtractLhxAllAttribute(SyntaxNode root, LanguageFile file)
        {
            var className = GetClassNameFromDocument(root);
            if (string.IsNullOrEmpty(className))
            {
                return;
            }

            // 查找所有带有LhxAllAttribute和TypeAttribute特性的地方
            var attributeLists = root.DescendantNodes().OfType<AttributeListSyntax>();
            foreach (var attributeList in attributeLists)
            {
                foreach (var attribute in attributeList.Attributes)
                {
                    var attributeName = attribute.Name.GetText().ToString();
                    if (attributeName != "LhxAll"&& attributeName != "LhxAllAttribute")
                    {
                        continue;
                    }
                    foreach (var argument in attribute.ArgumentList.Arguments)
                    {
                        if (argument.Expression is LiteralExpressionSyntax literal &&
                               literal.IsKind(SyntaxKind.StringLiteralExpression))
                        {
                            var stringValue = literal.Token.ValueText;
                            if (stringValue == "")
                            {
                                continue;
                            }
                            file.ReadValue(className, stringValue);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 提取UI控件名
        /// </summary>
        /// <param name="project"></param>
        /// <param name="file"></param>
        /// <returns></returns>
        public static async Task ExtractUINames(Project project, LanguageFile file)
        {
            var classToDesignerMap = new System.Collections.Generic.Dictionary<string, Document>();

            // 查找所有包含 RefreshString 方法的类
            foreach (var document in project.Documents)
            {
                if (!document.Name.EndsWith(".Designer.cs")) // 先处理非设计器文件
                {
                    var root = await document.GetSyntaxRootAsync();
                    var classesWithRefreshString = root.DescendantNodes()
                        .OfType<ClassDeclarationSyntax>()
                        .Where(classDecl => classDecl.DescendantNodes()
                            .OfType<MethodDeclarationSyntax>()
                            .Any(method => method.Identifier.Text == "RefreshString"));

                    foreach (var classDecl in classesWithRefreshString)
                    {
                        var className = classDecl.Identifier.Text;
                        Console.WriteLine($"Found class with RefreshString: {className}");

                        // 记录类名以便后续查找设计器文件
                        classToDesignerMap[className] = document;
                    }
                }
            }

            // 查找相关设计器文件并提取控件
            foreach (var kvp in classToDesignerMap)
            {
                var className = kvp.Key;
                var mainDocument = kvp.Value;

                // 查找设计器文件
                var designerDocument = project.Documents
                    .FirstOrDefault(doc => doc.Name.EndsWith($"{className}.Designer.cs"));

                if (designerDocument == null)
                {
                    continue;
                }

                var designerRoot = await designerDocument.GetSyntaxRootAsync();
                var designerClass = designerRoot.DescendantNodes()
                    .OfType<ClassDeclarationSyntax>()
                    .FirstOrDefault(classDecl => classDecl.Identifier.Text == className);

                if (designerClass != null)
                {
                    // 提取控件（字段和属性）
                    var fields = designerClass.Members
                        .OfType<FieldDeclarationSyntax>();

                    var properties = designerClass.Members
                        .OfType<PropertyDeclarationSyntax>();

                    foreach (var field in fields)
                    {
                        string text = string.Join(", ", field.Declaration.Variables.Select(v => v.Identifier.Text));
                        if (string.IsNullOrEmpty(text) || !text.Contains("_"))
                        {
                            continue;
                        }
                        string readText = text.Split('_').LastOrDefault();
                        file.ReadValue(className, readText);
                    }
                }
            }
        }

        /// <summary>
        /// 从类文件中提取出语言文件
        /// </summary>
        /// <param name="document"></param>
        /// <param name="projectFileName"></param>
        /// <returns></returns>
        public static async Task ExtractLangFromCsFile(Document document,LanguageFile file)
        {
            var root = await document.GetSyntaxRootAsync();
            var semanticModel = await document.GetSemanticModelAsync();
            ExtractLanguageMgrRead(root, file);
           // ExtractLhxAllAttribute(root, file);
            ExtractEnumDisplayName(root, file);
            ExtractTypeAttribute(semanticModel,root,file);
        }

        /// <summary>
        /// 提取DisplayName
        /// </summary>
        /// <param name="root"></param>
        /// <param name="file"></param>
        public static void ExtractEnumDisplayName(SyntaxNode root, LanguageFile file)
        {
            var enumDeclarations = root.DescendantNodes()
                    .OfType<EnumDeclarationSyntax>();

            foreach (var enumDeclaration in enumDeclarations)
            {
                var enumName = enumDeclaration.Identifier.Text;
                foreach (var member in enumDeclaration.Members)
                {
                    var attributeLists = member.AttributeLists;
                    foreach (var attributeList in attributeLists)
                    {
                        foreach (var attribute in attributeList.Attributes)
                        {
                            var attributeName = attribute.Name.ToString();
                            if (attributeName.Contains("LhxDisplayName"))
                            {
                                if (attribute.ArgumentList != null)
                                {
                                    foreach (var argument in attribute.ArgumentList.Arguments)
                                    {
                                        if (argument.Expression is LiteralExpressionSyntax literal)
                                        {
                                            file.ReadValue(enumName, literal.Token.ValueText);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

            }
        }

        /// <summary>
        /// 提取TypeAttribute
        /// </summary>
        /// <param name="semanticModel"></param>
        /// <param name="syntaxRoot"></param>
        /// <param name="file"></param>
        public static void ExtractTypeAttribute(SemanticModel semanticModel, SyntaxNode syntaxRoot, LanguageFile file)
        {
            var className = GetClassNameFromDocument(syntaxRoot);
            if (string.IsNullOrEmpty(className))
            {
                return;
            }

            // 查找所有具有 TypeAttribute 或其子类的特性节点
            var attributeLists = syntaxRoot.DescendantNodes()
                .OfType<AttributeListSyntax>()
                .Where(attrList => attrList.Attributes.Any(attr =>IsTypeAttributeOrSubclass(attr, semanticModel)));

            foreach (var attributeList in attributeLists)
            {
                foreach (var attribute in attributeList.Attributes)
                {
                    var attributeName = attribute.Name.GetText().ToString();
                    if (attribute.ArgumentList == null)
                    {
                        continue;
                    }
                    int argIndex = 0;
                    foreach (var argument in attribute.ArgumentList.Arguments)
                    {
                        if (argument.Expression is LiteralExpressionSyntax literal &&
                               literal.IsKind(SyntaxKind.StringLiteralExpression))
                        {
                            var stringValue = literal.Token.ValueText;
                            if (stringValue == ""|| argIndex>=3)//只需要读前三个参数
                            {
                                continue;
                            }
                            file.ReadValue(className, stringValue);
                            argIndex++;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 判断是否为TypeAttribute或者其子类
        /// </summary>
        /// <param name="attribute"></param>
        /// <param name="semanticModel"></param>
        /// <returns></returns>
        public static bool IsTypeAttributeOrSubclass(AttributeSyntax attribute, SemanticModel semanticModel)
        {
            var attributeSymbol = semanticModel.GetSymbolInfo(attribute.Name).Symbol as IMethodSymbol;
            if (attributeSymbol == null)
            {
                return false;
            }

            var containingType = attributeSymbol.ContainingType;
            if (containingType == null)
            {
                return false;
            }

            while (containingType != null)
            {
                if (containingType.Name == "TypeAttribute"||containingType.Name== "LhxAllAttribute")
                {
                    return true;
                }
                containingType = containingType.BaseType;
            }

            return false;
        }


        /// <summary>
        /// 获取cs文件的类名
        /// </summary>
        /// <param name="root"></param>
        /// <returns></returns>
        public static string GetClassNameFromDocument(SyntaxNode root)
        {
            // 这里是一个简化的示例，实际上您可能需要更复杂的逻辑来找到类名
            var classDecls = root.DescendantNodes().OfType<ClassDeclarationSyntax>();
            return classDecls.FirstOrDefault()?.Identifier.Text.ToString();
        }

        /// <summary>
        /// 判定调用方法是否为读取语言档的方法
        /// </summary>
        /// <param name="invocation"></param>
        /// <returns></returns>
        public static bool IsLanguageMgrReadInvocation(InvocationExpressionSyntax invocation)
        {
            var memberAccess = invocation.Expression as MemberAccessExpressionSyntax;
            return memberAccess != null &&
                   memberAccess.Name.Identifier.Text == "Read" &&
                   memberAccess.Expression is IdentifierNameSyntax identifierName &&
                   identifierName.Identifier.Text == "LanguageMgr";
        }

        /// <summary>
        /// 判定是否为语言档特性
        /// </summary>
        /// <param name="invocation"></param>
        /// <returns></returns>
        public static string ExtractStringLiteralFromInvocation(InvocationExpressionSyntax invocation)
        {
            var argumentList = invocation.ArgumentList;
            var argument = argumentList.Arguments.FirstOrDefault();
            if (argument != null)
            {
                var literal = argument.Expression as LiteralExpressionSyntax;
                return literal?.Token.ValueText;
            }
            return null;
        }


        #endregion

        #endregion
    }
}
